package com.android.graffiti;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;

import com.photoeditor.R;
import com.photoeditor.demo.model.image.collage.util.CollageGestureRecognizer;
import com.photoeditor.demo.model.image.tools.MatrixAnimation;
import com.photoeditor.demo.util.ImageRectUtils;

import java.util.Stack;


/**
 * 提供涂鸦绘制功能的自定义视图
 */
public class GraffitoView extends View implements CollageGestureRecognizer.Listener {

//    private static final String LOG_TAG = "GraffitoView";

    // 画笔类型
    public static final int BRUSH_TYPE_DEFAULT = 0x00000002;
    public static final int BRUSH_TYPE_CUSTOM = 0x00000000;
    public static final int BRUSH_TYPE_PENCIL = 0x00000001;
    public static final int BRUSH_TYPE_ROUND_PEN = 0x00000002;
    public static final int BRUSH_TYPE_FEATHER_PEN = 0x00000003;
    public static final int BRUSH_TYPE_HANDWRITE = 0x00000004;
    public static final int BRUSH_TYPE_ERASER = 0x10000001;

    // 画笔颜色
    public static final int BRUSH_COLOR_DEFAULT = Color.BLACK;

    private int mBrushType = BRUSH_TYPE_DEFAULT;

    // the elements to paint paths
    private Bitmap mBitmap;
    private Bitmap mExtraBitmap;
    private Canvas mCanvas;
    private Path mPath;

    // 记录画自定义图标的路径
    private CustomPath mCustomPath;
    private Bitmap mCustomBitmap;
    private Paint mCustomPaint;
    private Rect mCustomBitmapFitRect;
    private Paint mBitmapPaint;
    private Paint mPaint;
    private Paint mEraserPaint;
    private Paint mCachePaint;

    private Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_4444;

    private Rect mDstRect = new Rect();

    private boolean mIsMove = false;

    /**
     * 画emoji时是圆形图片，会造成画出来的效果比较小，所以这里相对画笔加大点
     */
    private static final float CUSTOM_ICON_SIZE_PADDING = 2f;

    /**
     * 获取位图设置
     *
     * @return 位图设置
     */
    public Bitmap.Config getBitmapConfig() {
        return mBitmapConfig;
    }

    /**
     * 设置位图设置
     *
     * @param bitmapConfig 位图设置
     */
    public void setBitmapConfig(Bitmap.Config bitmapConfig) {
        this.mBitmapConfig = bitmapConfig;
    }


    // the status values
    private boolean isEmpty = true;
    private boolean hasChange = false;

    // 画笔属性
    private float mPaintWidth = 10f;
    private int mPaintColor = BRUSH_COLOR_DEFAULT;
    private float mEraserWidth = 10f;
    private int mBackgroundColor = Color.TRANSPARENT;

    /**
     * 笔刷类型：  0颜色值 ， 1默认马赛克 ， 2图片马赛克
     */
    private int mColorType = 0;

    // 历史记录
    private Stack<AbsOperation> mHistoricalSteps = new Stack<AbsOperation>();

    private boolean mIsUsingVipBrush;

    // 监听器
    private OnDrawGraffitoListener mListener;
    private OnSizeChangedListener mSizeListener;

    /**
     * 用于标识当前有PopView不能绘制
     */
    private boolean mHasPopView = true;


    private Matrix mDrawMatrix;
    private Matrix mContentSupportMatrix;
    private Matrix mOppMatrix;
    private Matrix mCacheMatrix;


    /**
     * 是否支持缩放
     */
    private boolean mEnableScale = false;


    /**
     * 获取涂鸦绘制的监听器
     *
     * @return 涂鸦绘制的监听器
     */
    public OnDrawGraffitoListener getOnDrawGraffitoListener() {
        return mListener;
    }

    /**
     * 设置涂鸦绘制的监听器
     *
     * @param l 涂鸦绘制的监听器
     */
    public void setOnDrawGraffitoListener(OnDrawGraffitoListener l) {
        mListener = l;
    }

    /**
     * 获取控件大小变化的监听器
     *
     * @return 控件大小变化的监听器
     */
    public OnSizeChangedListener getOnSizeChangedListener() {
        return mSizeListener;
    }

    /**
     * 设置控件大小变化的监听器
     *
     * @param l 控件大小变化的监听器
     */
    public void setOnSizeChangedListener(OnSizeChangedListener l) {
        mSizeListener = l;
    }


    // 边界范围记录
    private Rect mContentRect = new Rect();
    private float mPadding = 0;


    /**
     * 获取图像内容的左边距（离原点，px）
     *
     * @return 图像内容的左边距
     */
    public float getContentLeft() {
        return Math.max(mContentRect.left - mPadding, 0);
    }

    /**
     * 获取图像内容的上边距（离原点，包含内边距，px）
     *
     * @return 图像内容的上边距
     */
    public float getContentTop() {
        return Math.max(mContentRect.top - mPadding, 0);
    }

    /**
     * 获取图像内容的右边距（离原点，包含内边距，px）
     *
     * @return 图像内容的右边距
     */
    public float getContentRight() {
        return mContentRect.right + mPadding;
    }

    /**
     * 获取图像内容的下边距（离原点，包含内边距，px）
     *
     * @return 图像内容的下边距
     */
    public float getContentBottom() {
        return mContentRect.bottom + mPadding;
    }

    /**
     * 获取图像内容的宽度（包含内边距，px）
     *
     * @return 图像内容的宽度
     */
    public int getContentWidth() {
        return (int) (getContentRight() - getContentLeft());
    }

    /**
     * 获取图像内容的高度（包含内边距，px）
     *
     * @return 图像内容的高度
     */
    public int getContentHeight() {
        return (int) (getContentBottom() - getContentTop());
    }

    /**
     * 获取图像内容的内边距(px)
     *
     * @return 图像内容的内边距(px)
     */
    public float getContentPadding() {
        return mPadding;
    }

    /**
     * 设置图像内容的内边距(px)
     *
     * @param padding 图像内容的内边距(px)
     */
    public void setContentPadding(float padding) {
        mPadding = padding;
    }


    /**
     * 获取图像内容的边界数据
     *
     * @return 图像内容的边界数据
     */
    public Rect getContentRect() {
        Rect rect = new Rect();
        rect.bottom = (int) getContentBottom();
        rect.left = (int) getContentLeft();
        rect.right = (int) getContentRight();
        rect.top = (int) getContentTop();
        return rect;
    }


    /**
     * @return the boolean value that represent if the graffito is empty
     */
    public boolean isEmpty() {
        return isEmpty;
    }

    /**
     * @return the boolean value that represent if this view havn't draw anything
     */
    public boolean hasChange() {
        return this.hasChange;
    }

    public boolean hasDrawContent() {
        if (mHistoricalSteps == null) {
            return false;
        }
        return !mHistoricalSteps.isEmpty();
    }

    public int getStepCount() {
        if (mHistoricalSteps == null) {
            return 0;
        }
        return mHistoricalSteps.size();
    }

    /**
     * @return the Bitmap that the view represent
     */
    public Bitmap getBitmap() {
        return this.mBitmap;
    }


    /**
     * 获取实际内容区域的{@link Bitmap}对象，自动裁剪空白的内容
     *
     * @return 实际内容区域的{@link Bitmap}对象
     */
    public Bitmap getContentBitmap() {
        int contentWidth = getContentWidth();
        int contentHeight = getContentHeight();
        if (contentWidth <= 0 || contentHeight <= 0) {
            //Loger.w(LOG_TAG, "Content's width or height must larger than 0!");
        }

        try {
            Bitmap newBitmap = Bitmap.createBitmap(
                    mExtraBitmap.getWidth(), mExtraBitmap.getHeight(), mBitmapConfig);
            Canvas canvas = new Canvas(newBitmap);
            if (this.mExtraBitmap != null && !this.mExtraBitmap.isRecycled()) {
                canvas.drawBitmap(mExtraBitmap, 0, 0, mBitmapPaint);
            } else {
                canvas.drawColor(mBackgroundColor);  // TODO 预设底色
            }

            if (mBitmap != null && !mBitmap.isRecycled()) {

                canvas.drawBitmap(mBitmap,
                        0 - getContentLeft(),
                        0 - getContentTop(),
                        this.mBitmapPaint);
            } else {
            }

            return newBitmap;

        } catch (OutOfMemoryError er) {
            return null;

        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 经获取绘制的内容，不包括原图
     *
     * @return
     */
    public Bitmap getPaintedContentOnly() {
        try {
            Bitmap newBitmap = Bitmap.createBitmap(
                    mExtraBitmap.getWidth(), mExtraBitmap.getHeight(), mBitmapConfig);
            Canvas canvas = new Canvas(newBitmap);
            if (mBitmap != null && !mBitmap.isRecycled()) {
                canvas.drawColor(Color.TRANSPARENT);
                canvas.drawBitmap(mBitmap,
                        0 - getContentLeft(),
                        0 - getContentTop(),
                        this.mBitmapPaint);
            }
            return newBitmap;

        } catch (OutOfMemoryError er) {
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    public boolean paintContentOnly(Canvas canvas, float scale) {
        if (mBitmap != null && !mBitmap.isRecycled()) {
            canvas.save();
            canvas.scale(scale, scale);
            if (mBoundRect != null) {
                canvas.translate(mContentRect.left - mBoundRect.left, mContentRect.top - mBoundRect.top);
            }
            canvas.drawBitmap(mBitmap, 0, 0, this.mBitmapPaint);
            canvas.restore();
            return true;
        }
        return false;
    }

    public Bitmap paintContentOnly(int width, int height, float scale) {
        if (mBitmap != null && !mBitmap.isRecycled()) {
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            canvas.save();
            canvas.scale(scale, scale);
            if (mBoundRect != null) {
                canvas.translate(mContentRect.left - mBoundRect.left, mContentRect.top - mBoundRect.top);
            }
            canvas.drawBitmap(mBitmap, 0, 0, this.mBitmapPaint);
            canvas.restore();
            return bitmap;
        }
        return null;
    }

    /**
     * @param bitmap the Bitmap to set
     */
    public void setBitmap(Bitmap bitmap) {
        if (bitmap != null && !bitmap.isRecycled()) {
            if (this.mCanvas != null) {
                this.mCanvas.drawBitmap(bitmap, 0, 0, this.mBitmapPaint);
                invalidate();   // redraw on the canvas
            } else {
                if (this.mBitmap != null) {
                    this.mBitmap.recycle();
                }
                this.mBitmap = bitmap;
            }
            this.isEmpty = false;
        }
    }


    /**
     * 获取额外的{@link Bitmap}图像
     *
     * @return 额外的{@link Bitmap}图像
     */
    public Bitmap getExtraBitmap() {
        return mExtraBitmap;
    }

    /**
     * 设置额外的{@link Bitmap}图像
     *
     * @param bitmap       额外的{@link Bitmap}图像
     * @param updateStatus 是否需要更新当前的状态
     */
    public void setExtraBitmap(Bitmap bitmap, boolean updateStatus) {
        if (mHistoricalSteps == null) {
            return;
        }
        if (bitmap == null || bitmap.isRecycled()) {
            return;
        }
        /*if (mExtraBitmap != null && !mExtraBitmap.isRecycled()) {
            mExtraBitmap.recycle();
        }*/
        this.mExtraBitmap = bitmap;
        this.isEmpty = true;
        if (updateStatus) {
            this.hasChange = true;
        }
        if (mIsInit) {
            initInformation();
        }
    }

    /**
     * 更新外部图片而不清楚历史记录
     *
     * @param bitmap
     */
    public void updateExtraBitmap(Bitmap bitmap) {
        if (mHistoricalSteps == null) {
            return;
        }
        if (bitmap == null || bitmap.isRecycled()) {
            return;
        }
        if (mExtraBitmap != null && !mExtraBitmap.isRecycled()) {
            mExtraBitmap.recycle();
        }
        this.mExtraBitmap = bitmap;
        mContentSupportMatrix = new Matrix();
        mDrawMatrix = new Matrix();
        mOppMatrix = new Matrix();
        mCacheMatrix = new Matrix();
        createNewDrawCanvas();
        if (this.mCanvas != null) {
            mCanvas.drawColor(Color.TRANSPARENT, Mode.SRC);
            drawBitmapIntoCanvas(mExtraBitmap);
            if (!mHistoricalSteps.isEmpty()) {
                if (!mHistoricalSteps.isEmpty()) {
                    mContentRect = mHistoricalSteps.peek().getContentRect();
                    this.isEmpty = false;
                } else {
                    mContentRect = new Rect();
                    resetContentBorder(getWidth(), getHeight());
                }
                // 重新绘制之前的涂鸦
                restoreHistory();
            }
        }
    }

    /**
     * 初始化两个Bitmap的信息
     */
    private void initInformation() {
        if (mExtraBitmap == null || mExtraBitmap.isRecycled()) return;
        createNewDrawCanvas();
        if (this.mCanvas != null) {
            // 先清除现有内容
            mCanvas.drawColor(Color.TRANSPARENT, Mode.SRC);

            drawBitmapIntoCanvas(mExtraBitmap);
            clearHistory();
            invalidate();

        }
    }


    /**
     * 直接在指定位置插入位图图像
     *
     * @param bitmap 要插入的位图图像
     * @param x      图像的X坐标位置(px)
     * @param y      图像的Y坐标位置(px)
     */
    public void insertBitmap(Bitmap bitmap, float x, float y) {
        if (bitmap == null || bitmap.isRecycled()) return;

        InsertImageOperation operation =
                new InsertImageOperation(bitmap, (int) x, (int) y);
        operation.operate();
        mHistoricalSteps.push(operation);

        mContentRect = new Rect(mContentRect);

        if (mListener != null) {
            mListener.onStrokeFinish(this, x, y);
        }
    }


    /**
     * 在画板你上绘制指定的{@link Bitmap}图像，图像将会拉伸并自适应居中
     *
     * @param bitmap 要绘制指定的{@link Bitmap}图像
     */
    private void drawBitmapIntoCanvas(Bitmap bitmap) {
        int oriWidth = bitmap.getWidth();
        int oriHeight = bitmap.getHeight();
        int newWidth;
        int newHeight;
        int offsetX = 0;
        int offserY = 0;

        if (oriWidth <= getWidth() && oriHeight <= getHeight()) {
            offsetX = (getWidth() - oriWidth) / 2;
            offserY = (getHeight() - oriHeight) / 2;
        } else {
            float radio = (float) oriWidth / (float) oriHeight;

            if (radio < ((float) getWidth() / (float) getHeight())) {
                newHeight = getHeight();
                newWidth = (int) (newHeight * radio);
                offsetX = (getWidth() - newWidth) / 2;
                offserY = 0;
            } else {
                newWidth = getWidth();
                newHeight = (int) (newWidth / radio);
                offsetX = 0;
                offserY = (getHeight() - newHeight) / 2;
            }
        }

        mDstRect = new Rect(0, 0, oriWidth, oriHeight);

        mContentRect.left = Math.min(offsetX, mContentRect.left);
        mContentRect.right = Math.max(oriWidth + offsetX, mContentRect.right);
        mContentRect.top = Math.min(offserY, mContentRect.top);
        mContentRect.bottom = Math.max(oriHeight + offserY, mContentRect.bottom);

        mNewWidth = oriWidth;
        mNewHeight = oriHeight;

        RectF defaultRect = new RectF(mDstRect);
        mContentSupportMatrix.reset();
        mContentSupportMatrix.setRectToRect(defaultRect, mViewRect, Matrix.ScaleToFit.CENTER);
        mDefautDrawableRect.set(defaultRect);
        mContentSupportMatrix.mapRect(mDefautDrawableRect);
        setDrawMatrix(countDrawMatrix());
    }


    /**
     * @return the Paint that determined how to draw path on view
     */
    public Paint getPaint() {
        return mPaint;
    }


    public void setCustomResource(int iconResId) {
        mBrushType = BRUSH_TYPE_CUSTOM;
        mCustomBitmap = BitmapFactory.decodeResource(getResources(), iconResId);
    }


    /**
     * 获取画笔的类型
     *
     * @return 画笔的类型
     */
    public int getBrushType() {
        return mBrushType;
    }

    /**
     * 设置画笔的类型
     *
     * @param type 画笔的类型
     */
    public void setBrushType(int type) {
        if (mPaint == null) {
            buildPathPaint();
        }


        mPaint.setColor(mPaintColor);
        mPaint.setStrokeWidth(mPaintWidth);

        switch (type) {
            case BRUSH_TYPE_PENCIL:
                mPaint.setStrokeCap(Paint.Cap.SQUARE);
                mPaint.setMaskFilter(null);
                mBrushType = type;
                break;

            case BRUSH_TYPE_ROUND_PEN:
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                mPaint.setMaskFilter(null);
                mBrushType = type;
                break;

            case BRUSH_TYPE_FEATHER_PEN:
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                mPaint.setMaskFilter(new BlurMaskFilter(6, BlurMaskFilter.Blur.NORMAL));
                mBrushType = type;
                break;

            case BRUSH_TYPE_HANDWRITE:
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                mPaint.setMaskFilter(new BlurMaskFilter(2, BlurMaskFilter.Blur.NORMAL));
                mBrushType = type;
                break;

            case BRUSH_TYPE_ERASER:
                mPaint.setStrokeCap(Paint.Cap.SQUARE);
                mPaint.setMaskFilter(null);
                mPaint.setColor(mBackgroundColor);
                mPaint.setStrokeWidth(mEraserWidth);
                mEraserPaint.setStrokeWidth(mEraserWidth);
                mBrushType = type;
                break;

            default:
                break;
        }
    }


    /**
     * 获取画笔的宽度
     *
     * @return 画笔的宽度(px)
     */
    public float getBrushWidth() {
        if (mPaint != null) {
            return mPaint.getStrokeWidth();
        } else {
            return 0;
        }
    }

    /**
     * 设置画笔的宽度
     *
     * @param width 画笔的宽度(px)
     */
    public void setBrushWidth(float width) {
        if (mPaint != null) {
            buildPathPaint();
            mPaint.setStrokeWidth(width);
        }

        if (mBrushType == BRUSH_TYPE_ERASER) {
            mEraserWidth = width;
            if (mEraserPaint != null) {
                mEraserPaint.setStrokeWidth(width);
            }
        } else {
            mPaintWidth = width;
        }


    }


    /**
     * 强制设置橡皮擦的宽度，
     * <b>注意：当前画笔为橡皮擦时，{@link GraffitoView#setBrushWidth(float)}
     * 也可以达到同样的效果</b>
     *
     * @param width 画笔的宽度(px)
     */
    public void setEraserWidth(float width) {
        if (mEraserPaint != null) {
            mEraserWidth = width;
            mEraserPaint.setStrokeWidth(width);
        }
        if (mPaint != null) {
            mPaint.setStrokeWidth(width);
        }
    }


    /**
     * 获取画笔的颜色
     *
     * @return 画笔的颜色
     */
    public int getBrushColor() {
        if (mPaint != null) {
            return mPaint.getColor();
        } else {
            return BRUSH_COLOR_DEFAULT;
        }
    }

    /**
     * 设置画笔的颜色
     *
     * @param color 画笔的颜色
     */
    public void setBrushColor(int color) {
        if (mPaint != null) {
            buildPathPaint();
            mPaint.setColor(color);
        }
        mPaintColor = color;


        //设置马赛克图片
        if (getColorType() == 1) {

            setMosaic();

        } else if (getColorType() == 2) {
            Bitmap mosaicBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_edit_doodle_mosaic2);
            Shader mShader = new BitmapShader(mosaicBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
            mPaint.setShader(mShader);
        } else if (getColorType() == 3) {
            Bitmap mosaicBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_edit_doodle_mosaic3);
            Shader mShader = new BitmapShader(mosaicBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
            mPaint.setShader(mShader);
        } else if (getColorType() == 4) {
            Bitmap mosaicBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_edit_doodle_mosaic4);
            Shader mShader = new BitmapShader(mosaicBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
            mPaint.setShader(mShader);
        } else {
            mPaint.setShader(null);
            mPaint.setColor(mPaintColor);
        }
    }

    /**
     * 设置马赛克图片宽度、返回马赛克图片
     */
    private void setMosaic() {

        Bitmap contentBitmap = getContentBitmap();
        if (contentBitmap == null || mNewWidth == 0 || mNewHeight == 0) {
            return;
        }

        Bitmap scaleBitmap = Bitmap.createScaledBitmap(contentBitmap, mNewWidth, mNewHeight, true);

        if (scaleBitmap == null) {
            return;
        }

        Bitmap mosaicBitmap = mosaicUtils.getMosaicImage(scaleBitmap);
        Shader mShader = new BitmapShader(mosaicBitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
        mPaint.setShader(mShader);

        if (contentBitmap != null && !contentBitmap.isRecycled() && contentBitmap != scaleBitmap) {
            contentBitmap.recycle();
        }


    }


    public int getColorType() {
        return this.mColorType;
    }

    /**
     * 设置笔刷类型
     *
     * @param type
     */
    public void setColorType(int type) {
        this.mColorType = type;
    }


    /**
     * 获取预设的背景颜色
     *
     * @return 预设的背景颜色
     */
    public int getCanvasBackgroundColor() {
        return mBackgroundColor;
    }

    /**
     * 设置预设的背景颜色
     *
     * @param color 预设的背景颜色
     */
    public void setCanvasBackgroundColor(int color) {
        mBackgroundColor = color;
    }


    public GraffitoView(Context context) {
        super(context);
        initializeCanvas();
    }

    public GraffitoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mosaicUtils = new MosaicUtils(context);

        initializeCanvas();
        initializeWithAttrs(context, attrs);

    }

    public GraffitoView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initializeCanvas();
        initializeWithAttrs(context, attrs);
    }

    /**
     * Initialize the element such as canvas and paint in this view.
     */
    private void initializeCanvas() {
        mContentSupportMatrix = new Matrix();
        mDrawMatrix = new Matrix();
        mOppMatrix = new Matrix();
        mCacheMatrix = new Matrix();
        buildPathPaint();
        this.mPath = new Path();
        mCustomPath = new CustomPath();
        mCustomPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCustomBitmapFitRect = new Rect();
        this.mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);

        mEraserPaint = new Paint(mPaint);
        mEraserPaint.setStrokeCap(Paint.Cap.ROUND);
        mEraserPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        mEraserPaint.setStrokeWidth(mEraserWidth);

        mGestureRecognizer = new CollageGestureRecognizer(getContext(), this);

        mCachePaint = new Paint();
        mViewRect = new RectF();
        mDefautDrawableRect = new RectF();
    }


    /**
     * Initialize the element with attributes in XML
     *
     * @param context
     * @param attrs
     */
    private void initializeWithAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.GraffitoView);

        mPadding = typedArray.getDimension(R.styleable.GraffitoView_contentPadding, 0);
        mBackgroundColor = typedArray.getColor(
                R.styleable.GraffitoView_canvasBackground, Color.TRANSPARENT);

        typedArray.recycle();
    }


    /**
     * Build a default paint that draw the path.
     *
     * @return a paint to draw path
     */
    private Paint buildPathPaint() {
        if (mPaint == null) {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        }

        //如果设置为true，部分手机马赛克功能会出现黑线条
        mPaint.setAntiAlias(false);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        return mPaint;
    }

    private MosaicUtils mosaicUtils = null;


    /**
     * Called when the method 'invalidate()' called.
     */
    @Override
    protected void onDraw(Canvas canvas) {
        if (mMatrixAnimation != null && !mMatrixAnimation.hasEnded()) {
            // 如果动画还没结束，则获取当前变换过程的矩阵
            mMatrixAnimation.getTransformation(
                    AnimationUtils.currentAnimationTimeMillis(),
                    mTransformation);
            Matrix currMatrix = mTransformation.getMatrix();

            if (currMatrix.equals(getDrawMatrix())) {
                // 如果矩阵没有变化，可能是时间值间隔太短或动画刚刚开始，这时手动重绘
                invalidate();
            } else {
                // 设置当前的矩阵变换，设置后会重绘
                mOppMatrix.set(mTransformation.getMatrix());
                setDrawMatrix(countDrawMatrix());
            }
        } else {
            // 动画已经结束播放了，重新修改状态值
            mIsAnimationRunning = false;
        }

        if (mBoundRect != null) {
            canvas.clipRect(mBoundRect);
        }

        // draw the historical paths
        if (this.mExtraBitmap != null && !this.mExtraBitmap.isRecycled()
                && this.mBitmapPaint != null) {
            canvas.drawBitmap(mExtraBitmap, getDrawMatrix(), mBitmapPaint);
        }

        if (mCanvas == null) {
            requestLayout();
            return;
        }

        if (mBrushType == BRUSH_TYPE_ERASER) {
            if (this.mPath != null && this.mEraserPaint != null) {
                mCachePaint.set(mEraserPaint);
                mCachePaint.setStrokeWidth(mCachePaint.getStrokeWidth() / getSupportScale());
                mCacheMatrix.set(getDrawMatrix());
                mCacheMatrix.invert(mCacheMatrix);
                mCanvas.save();
                mCanvas.clipRect(getChangedViewRect(mCacheMatrix));
                mCanvas.drawPath(this.mPath, this.mCachePaint);
                mCanvas.restore();
            }
        } else if (mBrushType == BRUSH_TYPE_CUSTOM) {
            if (mCustomBitmap != null && mCustomPaint != null && mCustomPath != null) {
                mCacheMatrix.set(getDrawMatrix());
                mCacheMatrix.invert(mCacheMatrix);
                mCanvas.save();
                //mCanvas.clipRect(getChangedViewRect(mCacheMatrix));
                float scale = getSupportScale();
                int radius = (int) ((mPaintWidth * CUSTOM_ICON_SIZE_PADDING) / scale / 2);
                for (int i = 0; i < mCustomPath.size(); i++) {
                    mCustomBitmapFitRect.left = (int) (mCustomPath.getPointAt(i).x - radius);
                    mCustomBitmapFitRect.top = (int) (mCustomPath.getPointAt(i).y - radius);
                    mCustomBitmapFitRect.right = mCustomBitmapFitRect.left + radius * 2;
                    mCustomBitmapFitRect.bottom = mCustomBitmapFitRect.top + radius * 2;
                    mCanvas.drawBitmap(mCustomBitmap, null, mCustomBitmapFitRect, mCustomPaint);
                }
                mCanvas.restore();
            }
        } else {
            // draw the path which the user draw just now
            if (this.mPath != null && this.mPaint != null) {
                mCachePaint.set(mPaint);
                mCachePaint.setStrokeWidth(mCachePaint.getStrokeWidth() / getSupportScale());
                mCacheMatrix.set(getDrawMatrix());
                mCacheMatrix.invert(mCacheMatrix);
                mCanvas.save();
                mCanvas.clipRect(getChangedViewRect(mCacheMatrix));
                mCanvas.drawPath(this.mPath, this.mCachePaint);
                mCanvas.restore();
            }
        }

        // draw the historical paths
        if (this.mBitmap != null && !this.mBitmap.isRecycled()
                && this.mBitmapPaint != null) {
            canvas.drawBitmap(this.mBitmap, getDrawMatrix(), this.mBitmapPaint);
        }
    }

    private RectF mBoundRect;

    public void setBoundRect(RectF boundRect) {
        mBoundRect = boundRect;
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private int mNewWidth;
    private int mNewHeight;


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            initViewRect(ImageRectUtils.getViewRect(this));
        }
    }

    /**
     * Called when the size of this view changed.
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 触发事件
        if (mSizeListener != null) {
            mSizeListener.onSizeChanged(this, w, h);
        }
    }

    /**
     * 设置是否支持缩放，默认为true
     *
     * @param enableScale
     */
    public void setScalable(boolean enableScale) {
        mEnableScale = enableScale;
    }

    /**
     * Called when the user touch the view and move finger till he leave the view.
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) return false;
        if (mHasPopView) {//当存在PopView是拦截掉
            // 触发事件
            if (mListener != null && event.getAction() == MotionEvent.ACTION_DOWN) {
                mListener.onNeedClosePopView();
            }
        }
        float x = event.getX();
        float y = event.getY();

        int count = event.getPointerCount();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mIsMove = false;
                if (count == 1) {
                    mTouchMode = TOUCH_DRAW;
                    touchAndStart(x, y);
                    invalidate();   // redraw on the canvas
                } else {
                    mTouchMode = TOUCH_SCALE_OR_MOVE;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mTouchMode == TOUCH_DRAW) {
                    touchAndMove(x, y);
                    invalidate();   // redraw on the canvas
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (mTouchMode == TOUCH_DRAW) {
                    if (mBrushType == BRUSH_TYPE_CUSTOM) {
                        if (mCustomPath != null && mCustomPath.size() != 0) {
                            touchAndUp();
                            undo();
                            invalidate();
                            if (mListener != null) {
                                mListener.onStrokeFinish(this, mX, mY);
                            }
                        }
                    } else {
                        if (mIsMove) {//移动了 一定有绘制东西
                            touchAndUp();
                            invalidate();
                        }
                    }
                }
                if (count == 2) {
                    mTouchMode = TOUCH_SCALE_OR_MOVE;
                } else {
                    mTouchMode = TOUCH_NONE;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mTouchMode == TOUCH_DRAW) {
                    touchAndUp();
                    invalidate();   // redraw on the canvas
                }
                mIsMove = false;
                this.hasChange = true;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                if (count == 2) {
                    mTouchMode = TOUCH_NONE;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        if (mEnableScale) {
            mGestureRecognizer.onGraffitoViewTouchEvent(event);
        }
        return true;
    }


    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touchAndStart(float x, float y) {
        if (mBrushType == BRUSH_TYPE_CUSTOM && mCustomPath == null) {
            return;
        } else if (mPath == null) {
            return;
        }
        float src[] = new float[2];
        src[0] = x;
        src[1] = y;
        mCacheMatrix.set(getDrawMatrix());
        mCacheMatrix.invert(mCacheMatrix);
        mCacheMatrix.mapPoints(src);
        x = src[0];
        y = src[1];

        if (mBrushType == BRUSH_TYPE_CUSTOM) {
            mCustomPath.addPoint(new PointF(x, y));
        } else {
            mPath.reset();
            mPath.moveTo(x, y);
        }
        mX = x;
        mY = y;

        if (mBrushType != BRUSH_TYPE_ERASER) {
            measureContentBorder(x, y);
        }

        // 触发事件
        if (mListener != null) {
            mListener.onNewStroke(this, mX, mY);
        }
    }

    private void touchAndMove(float x, float y) {
        if (mBrushType == BRUSH_TYPE_CUSTOM && mCustomPath == null) {
            return;
        } else if (mPath == null) {
            return;
        }
        float src[] = new float[2];
        src[0] = x;
        src[1] = y;
        mCacheMatrix.set(getDrawMatrix());
        mCacheMatrix.invert(mCacheMatrix);
        mCacheMatrix.mapPoints(src);
        x = src[0];
        y = src[1];

        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);

        if (mBrushType == BRUSH_TYPE_CUSTOM) {
            // 特意将边长稍微减少一点让图标之间看起来更紧凑
            float sideLength = mPaintWidth * CUSTOM_ICON_SIZE_PADDING / getSupportScale();
            // 要画的是正方形，只要满足垂直方向距离大于等于边长即需要添加绘制点
            if (dx >= sideLength || dy >= sideLength) {
                float pointX = x;
                float pointY = y;
                float slope = dy / dx;
                // 按x轴偏移计算需要补画的个数
                int newPointCount = 0;
                // 是否按X轴的偏移计算
                boolean baseOnX = false;
                if (dx > dy) {
                    baseOnX = true;
                    newPointCount = (int) (dx / sideLength);
                } else {
                    newPointCount = (int) (dy / sideLength);
                }

                // 当前点在上一个点的左上方向
                if (x <= mX && y <= mY) {
                    for (int i = 0; i < newPointCount; i++) {
                        if (baseOnX) {
                            pointX = mX - sideLength * (i + 1);
                            pointY = mY - slope * sideLength * (i + 1);
                        } else {
                            pointY = mY - sideLength * (i + 1);
                            pointX = mX - sideLength * (i + 1) / slope;
                        }
                        mCustomPath.addPoint(new PointF(pointX, pointY));
                    }
                }
                // 当前点在上一个点的左下方向
                else if (x <= mX && y >= mY) {
                    for (int i = 0; i < newPointCount; i++) {
                        if (baseOnX) {
                            pointX = mX - sideLength * (i + 1);
                            pointY = mY + slope * sideLength * (i + 1);
                        } else {
                            pointY = mY + sideLength * (i + 1);
                            pointX = mX - sideLength * (i + 1) / slope;
                        }
                        mCustomPath.addPoint(new PointF(pointX, pointY));
                    }
                }
                // 当前点在上一个点的右上方向
                else if (x >= mX && y <= mY) {
                    for (int i = 0; i < newPointCount; i++) {
                        if (baseOnX) {
                            pointX = mX + sideLength * (i + 1);
                            pointY = mY - slope * sideLength * (i + 1);
                        } else {
                            pointY = mY - sideLength * (i + 1);
                            pointX = mX + sideLength * (i + 1) / slope;
                        }
                        mCustomPath.addPoint(new PointF(pointX, pointY));
                    }
                }
                // 当前点在上一个点的右下方向
                else if (x >= mX && y >= mY) {
                    for (int i = 0; i < newPointCount; i++) {
                        if (baseOnX) {
                            pointX = mX + sideLength * (i + 1);
                            pointY = mY + slope * sideLength * (i + 1);
                        } else {
                            pointY = mY + sideLength * (i + 1);
                            pointX = mX + sideLength * (i + 1) / slope;
                        }
                        mCustomPath.addPoint(new PointF(pointX, pointY));
                    }
                }
                mX = pointX;
                mY = pointY;
                mIsMove = true;
            }

        } else if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
            mIsMove = true;
        }

        if (mBrushType != BRUSH_TYPE_ERASER) {
            measureContentBorder(x, y);
        }
    }

    private void touchAndUp() {
        if (mBrushType == BRUSH_TYPE_CUSTOM && mCustomPath == null) {
            return;
        } else if (mPath == null) {
            return;
        }
        if (mBrushType != BRUSH_TYPE_CUSTOM) {
            if (!mIsMove) {
                mPath.lineTo(mX + 0.01f, mY + 0.01f);
            } else {
                mPath.lineTo(mX + 0.001f, mY + 0.001f);
            }
        }
        if (mCanvas == null) {
            return;
        }

        // commit the path to our offscreen
        Paint currentPaint = mCachePaint;
        Matrix canvasMatrix = new Matrix(getDrawMatrix());
        canvasMatrix.invert(canvasMatrix);
        RectF clipRect = getChangedViewRect(canvasMatrix);
        if (mBrushType == BRUSH_TYPE_ERASER && mEraserPaint != null) {  // 橡皮擦
            //这种是变幻mCanvas达到目标效果
            mCachePaint.set(mEraserPaint);
            mCachePaint.setStrokeWidth(mCachePaint.getStrokeWidth() / getSupportScale());
            mCanvas.save();
            mCanvas.clipRect(clipRect);
            mCanvas.drawPath(mPath, mCachePaint);
            mCanvas.restore();
            currentPaint = mCachePaint;
        } else if (mBrushType == BRUSH_TYPE_CUSTOM) {
            if (mCustomPath.size() != 0) {
                mCanvas.save();
                // mCanvas.clipRect(clipRect);
                for (int i = 0; i < mCustomPath.size(); i++) {
                    int radius = (int) (mPaintWidth * CUSTOM_ICON_SIZE_PADDING / getSupportScale() / 2);
                    int left = (int) (mCustomPath.getPointAt(i).x - radius);
                    int top = (int) (mCustomPath.getPointAt(i).y - radius);
                    int right = left + radius * 2;
                    int bottom = top + radius * 2;
                    Rect fitRect = new Rect(left, top, right, bottom);
                    mCanvas.drawBitmap(mCustomBitmap, null, fitRect, mCustomPaint);
                }
                mCanvas.restore();
                isEmpty = false;
            }
        } else {  // 普通画笔
            if (mPaint != null) {
                mCachePaint.set(mPaint);
                mCachePaint.setStrokeWidth(mCachePaint.getStrokeWidth() / getSupportScale());
                mCanvas.save();
                mCanvas.clipRect(clipRect);
                mCanvas.drawPath(mPath, mCachePaint);
                mCanvas.restore();
                this.isEmpty = false;
                currentPaint = mCachePaint;
            }
        }

        // 如果已经有内容，则将该笔记入历史记录
        if (!this.isEmpty) {
            if (!mHistoricalSteps.empty() && mHistoricalSteps.peek() == null) {
                // 此处需要去掉历史记录中顶端的空值，
                // 当用户清空内容后，会在历史记录中插入空值以作标识，此时应清除该标识
                mHistoricalSteps.pop();

            }
            if (mBrushType == BRUSH_TYPE_CUSTOM) {
                mHistoricalSteps.push(new CustomDrawPathOperation(mIsUsingVipBrush, clipRect, mCustomPath, mCustomPaint, mContentRect, mPaintWidth, mCustomBitmap));
            } else {
                Paint currentEraserPaint = new Paint(currentPaint);
                mHistoricalSteps.push(new DrawPathOperation(mIsUsingVipBrush, clipRect, mPath, currentEraserPaint, mContentRect));
            }
        }

        if (mBrushType == BRUSH_TYPE_CUSTOM) {
            mCustomPath = new CustomPath();
        } else {
            mPath = new Path();
        }
        mPaint = new Paint(mPaint);
        mContentRect = new Rect(mContentRect);

        // 触发事件
        if (mListener != null) {
            mListener.onStrokeFinish(this, mX, mY);
        }
    }

    public void setUsingVipBrush(boolean usingVipBrush) {
        mIsUsingVipBrush = usingVipBrush;
    }

    public boolean hasUseVipBrush() {
        for (AbsOperation operation : mHistoricalSteps) {
            if (operation.IsVipBrush()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 度量实际图像内容的边界
     *
     * @param x 当前图像绘制点的X坐标
     * @param y 当前图像绘制点的Y坐标
     */
    private void measureContentBorder(float x, float y) {
        mContentRect.left = (int) Math.min(x - mPaintWidth / 2, mContentRect.left);
        mContentRect.right = (int) Math.max(x + mPaintWidth / 2, mContentRect.right);
        mContentRect.top = (int) Math.min(y - mPaintWidth / 2, mContentRect.top);
        mContentRect.bottom = (int) Math.max(y + mPaintWidth / 2, mContentRect.bottom);
    }


    /**
     * 重置实际内容边界
     *
     * @param width  内容的最大宽度
     * @param height 内容的最大高度
     */
    private void resetContentBorder(int width, int height) {
        mContentRect.left = 0;
        mContentRect.right = width;
        mContentRect.top = 0;
        mContentRect.bottom = height;
    }


    /**
     * Clear all content on the view.
     */
    public void clear() {
        clearContent();
        mHistoricalSteps.push(null);
        this.hasChange = true;
    }


    /**
     * Reset the status in the view and clear all content.
     */
    public void reset(int type) {
        mosaicUtils.reset();

        clearContent();

        //如果当前选中的是马赛克
        if (type == 1) {
            setMosaic();
        }

        clearHistory();

        this.hasChange = true;
        this.isEmpty = true;
        mIsUsingVipBrush = false;
    }


    /**
     * Just clear all drawing on the view.
     */
    private void clearContent() {


        if (mCanvas != null) {
            mCanvas.drawColor(Color.TRANSPARENT, Mode.SRC);
            invalidate();   // redraw on the canvas
        }

        resetContentBorder(getWidth(), getHeight());
        this.isEmpty = true;

    }


    /**
     * 撤销上一笔
     */
    public void undo() {
        if (mHistoricalSteps == null || mHistoricalSteps.isEmpty()) {
            return;
        }

        this.isEmpty = true;
        if (mCanvas != null) {
            mCanvas.drawColor(Color.TRANSPARENT, Mode.SRC);
            invalidate();   // redraw on the canvas
        }

        // 如果有置入图片，则重新绘制
        if (mExtraBitmap != null) {
        } else {
            // 移除遗留下来的插入图片操作
            if (mHistoricalSteps.peek() instanceof ImportOperation) {
                mHistoricalSteps.pop();
            }
        }

        if (!mHistoricalSteps.isEmpty()) {

            // 移除上一笔的内容
            AbsOperation op = mHistoricalSteps.pop();
            if (op != null) op.recycle();

            if (!mHistoricalSteps.isEmpty()) {
                mContentRect = mHistoricalSteps.peek().getContentRect();
                this.isEmpty = false;
            } else {
                mContentRect = new Rect();
                resetContentBorder(getWidth(), getHeight());
            }

            // 重新绘制之前的涂鸦
            restoreHistory();
        }
    }

    /**
     * 回复历史记录中所有的内容
     *
     * @return 最后绘制的线条
     */
    private void restoreHistory() {
        if (mCanvas == null) {
            return;
        }
        if (mHistoricalSteps == null) {
            return;
        }

        for (AbsOperation operation : mHistoricalSteps) {
            if (operation != null) operation.operate();
        }
        invalidate();
    }


    /**
     * 清空历史记录
     */
    private void clearHistory() {
        for (AbsOperation operation : mHistoricalSteps) {
            operation.recycle();
        }
        mHistoricalSteps.clear();
    }


    /**
     * 销毁资源
     */
    public void destory() {
        if (mBitmap != null && !mBitmap.isRecycled()) {
            mBitmap.recycle();
        }

        if (mExtraBitmap != null && !mExtraBitmap.isRecycled()) {
            mExtraBitmap.recycle();
        }

        if (mHistoricalSteps != null) {
            clearHistory();
        }
        mHistoricalSteps = null;

    }


    /**
     * 当用户画涂鸦时触发事件的监听器接口
     */
    public interface OnDrawGraffitoListener {

        /**
         * 用户开始画新的一笔时触发的事件
         */
        public void onNewStroke(View v, float x, float y);


        /**
         * 当用户完成一笔时触发的事件
         *
         * @param v
         * @param x
         * @param y
         */
        public void onStrokeFinish(View v, float x, float y);

        /**
         * 当存在PopView时 需要关闭时触发
         */
        public void onNeedClosePopView();
    }


    /**
     * 当控件大小变化时触发事件的监听器接口
     */
    public interface OnSizeChangedListener {

        /**
         * 当控件大小发生变化时触发的事件
         *
         * @param v
         * @param width
         * @param height
         */
        public void onSizeChanged(View v, int width, int height);
    }


    /**
     * 表示单次操作的抽象类
     */
    public static abstract class AbsOperation {
        private Rect mContentRect = null;

        private boolean mIsVipBrush;

        /**
         * 获取涂鸦内容的区域
         *
         * @return 涂鸦内容的区域
         */
        public Rect getContentRect() {
            return mContentRect;
        }

        /**
         * 设置涂鸦内容的区域
         *
         * @param contentRect 涂鸦内容的区域
         */
        public void setContentRect(Rect contentRect) {
            this.mContentRect = contentRect;
        }

        /**
         * 执行该次步骤的操作
         */
        protected abstract void operate();

        /**
         * 回收该次步骤的资源
         */
        protected abstract void recycle();

        protected void setIsVipBrush(boolean isVipBrush) {
            mIsVipBrush = isVipBrush;
        }

        protected boolean IsVipBrush() {
            return mIsVipBrush;
        }
    }


    /**
     * 表示单次导入图片操作的类
     */
    public class ImportOperation extends AbsOperation {

        @Override
        protected void operate() {
            // 不需要任何操作
        }

        @Override
        protected void recycle() {
            // 不需要任何操作
        }

        /**
         * 初始化一个单次导入图片操作
         *
         * @param rect 涂鸦内容的区域
         */
        public ImportOperation(Rect rect) {
            this.setContentRect(rect);
        }
    }

    /**
     * 表示单次画线操作的类
     */
    public class DrawPathOperation extends AbsOperation {
        private Paint mPaint = null;
        private Path mPath = null;

        private RectF mClipRect;

        /**
         * 获取该次画线操作所用的画笔对象
         *
         * @return 该次画线操作所用的画笔对象
         */
        public Paint getPaint() {
            return mPaint;
        }

        /**
         * 设置该次画线操作所用的画笔对象
         *
         * @param paint 该次画线操作所用的画笔对象
         */
        public void setPaint(Paint paint) {
            this.mPaint = paint;
        }

        /**
         * 获取该次画线操作所画的线条
         *
         * @return 该次画线操作所画的线条
         */
        public Path getPath() {
            return mPath;
        }

        /**
         * 设置该次画线操作所画的线条
         *
         * @param path 该次画线操作所画的线条
         */
        public void setPath(Path path) {
            this.mPath = path;
        }


        @Override
        protected void operate() {
            // TODO Auto-generated method stub
            if (mPath != null && mPaint != null) {
                mCanvas.save();
                mCanvas.clipRect(mClipRect);
                mCanvas.drawPath(mPath, mPaint);
                mCanvas.restore();
                isEmpty = false;
            }
        }

        @Override
        protected void recycle() {
            mPath = null;
            mPaint = null;
        }


        /**
         * 初始化一个画线操作对象
         *
         * @param path  该次画线操作所画的线条
         * @param paint 该次画线操作所用的画笔对象
         * @param rect  涂鸦内容的区域
         */
        public DrawPathOperation(boolean isVipBrush, RectF clipRect, Path path, Paint paint, Rect rect) {
            this.mClipRect = clipRect;
            this.mPaint = paint;
            this.mPath = path;
            this.setContentRect(rect);
            setIsVipBrush(isVipBrush);
        }
    }

    /**
     * 自定义图标操作
     */
    public class CustomDrawPathOperation extends AbsOperation {
        private Paint mPaint = null;
        private CustomPath mPath = null;
        private float mPaintWidth = 0;

        private RectF mClipRect;
        private Bitmap mBitmap;
        private Rect mBitmapRect = new Rect();


        /**
         * 设置该次画线操作所用的画笔对象
         *
         * @param paint 该次画线操作所用的画笔对象
         */
        public void setPaint(Paint paint) {
            this.mPaint = paint;
        }

        /**
         * 设置该次画线操作所画的线条
         *
         * @param path 该次画线操作所画的线条
         */
        public void setPath(CustomPath path) {
            this.mPath = path;
        }

        @Override
        protected void operate() {
            if (mBitmap != null && mPath != null) {
                mCanvas.save();
                // mCanvas.clipRect(mClipRect);
                float scale = getSupportScale();
                int radius = (int) (mPaintWidth * CUSTOM_ICON_SIZE_PADDING / scale / 2);
                for (int i = 0; i < mPath.size(); i++) {
                    mBitmapRect.left = (int) (mPath.getPointAt(i).x - radius);
                    mBitmapRect.top = (int) (mPath.getPointAt(i).y - radius);
                    mBitmapRect.right = mBitmapRect.left + radius * 2;
                    mBitmapRect.bottom = mBitmapRect.top + radius * 2;
                    mCanvas.drawBitmap(mBitmap, null, mBitmapRect, mPaint);
                }
                mCanvas.restore();
                isEmpty = false;
            }
        }

        @Override
        protected void recycle() {
            if (mPath != null) {
                mPath.clear();
            }
            mPaint = null;
        }


        /**
         * 初始化一个画线操作对象
         *
         * @param path  该次操作需绘制的点
         * @param paint 该次画线操作所用的画笔对象
         * @param rect  涂鸦内容的区域
         */
        public CustomDrawPathOperation(boolean isVipBrush, RectF clipRect, CustomPath path, Paint paint, Rect rect, float paintWidth, Bitmap bitmap) {
            mClipRect = clipRect;
            mPaint = paint;
            mPath = path;
            mPaintWidth = paintWidth;
            mBitmap = bitmap;
            setIsVipBrush(isVipBrush);
            setContentRect(rect);
        }
    }

    /**
     * 表示单次插入图像操作的类
     */
    public class InsertImageOperation extends AbsOperation {
        private Bitmap mInsBitmap = null;
        private int mPositionX = 0;
        private int mPositionY = 0;

        /**
         * 获取要插入的位图图像
         *
         * @return 要插入的位图图像
         */
        public Bitmap getBitmap() {
            return mInsBitmap;
        }

        /**
         * 设置要插入的位图图像
         *
         * @param bitmap 要插入的位图图像
         */
        public void setBitmap(Bitmap bitmap) {
            this.mInsBitmap = bitmap;
        }

        /**
         * 获取要插入的位置的X坐标值
         *
         * @return 要插入的位置的X坐标值
         */
        public int getPositionX() {
            return mPositionX;
        }

        /**
         * 设置要插入的位置的X坐标值
         *
         * @param x 要插入的位置的X坐标值
         */
        public void setPositionX(int x) {
            this.mPositionX = x;
        }

        /**
         * 获取要插入的位置的Y坐标值
         *
         * @return 要插入的位置的Y坐标值
         */
        public int getPositionY() {
            return mPositionY;
        }

        /**
         * 设置要插入的位置的Y坐标值
         *
         * @param y 要插入的位置的Y坐标值
         */
        public void setPositionY(int y) {
            this.mPositionY = y;
        }


        @Override
        protected void operate() {
            if (this.mInsBitmap == null || this.mInsBitmap.isRecycled()) {
                return;
            }

            if (mCanvas != null) {
                mCanvas.drawBitmap(mInsBitmap, mPositionX, mPositionY, mBitmapPaint);

                mContentRect.left = Math.min(mPositionX, mContentRect.left);
                mContentRect.right = Math.max(
                        mPositionX + mInsBitmap.getWidth(), mContentRect.right);
                mContentRect.top = Math.min(mPositionY, mContentRect.top);
                mContentRect.bottom = Math.max(
                        mPositionY + mInsBitmap.getHeight(), mContentRect.bottom);

                if (mContentRect.left < 0) mContentRect.left = 0;
                if (mContentRect.top < 0) mContentRect.top = 0;
                setContentRect(mContentRect);

                isEmpty = false;
                hasChange = true;
            }
        }

        @Override
        protected void recycle() {
            mInsBitmap.recycle();
            mInsBitmap = null;
        }


        /**
         * 初始化单次插入图像操作
         *
         * @param bitmap 要插入的位图图像
         * @param x      要插入的位置的X坐标值
         * @param y      要插入的位置的Y坐标值
         */
        public InsertImageOperation(Bitmap bitmap, int x, int y) {
            this.mInsBitmap = bitmap;
            this.mPositionX = x;
            this.mPositionY = y;
        }
    }

    public boolean isHasPopView() {
        return mHasPopView;
    }

    public void setHasPopView(boolean hasPopView) {
        mHasPopView = hasPopView;
    }

    @Override
    public boolean onSingleTapUp(float x, float y) {
        return true;
    }

    @Override
    public boolean onSingleTapComfirm(float x, float y) {
        return true;
    }

    @Override
    public boolean onDoubleTap(float x, float y) {
        return true;
    }

    @Override
    public boolean onScroll(float x, float y, float dx, float dy, float totalX, float totalY) {
        if (mTouchMode == TOUCH_SCALE_OR_MOVE) {
            float translateX = -dx;
            float translateY = -dy;

//       这段代码是不让他移出边界
            RectF displayRect = getDisplayRect(countDrawMatrix());
            /**
             * 一些特殊情况的处理
             */
            if (displayRect.width() <= (float) (getWidth())) {
                translateX = 0f;
            } else {
            }

            if (displayRect.height() <= getHeight()) {
                translateY = 0f;
            }

            if (displayRect.height() > getHeight()) {
                if (displayRect.top + translateY > 0f) {
                    translateY = -displayRect.top;
                } else if (displayRect.bottom + translateY < getHeight()) {
                    translateY = getHeight() - displayRect.bottom;
                }
            }
            if (displayRect.width() > getWidth()) {
                if (displayRect.left + translateX > 0f) {
                    translateX = -displayRect.left;
                } else if (displayRect.right + translateX < getWidth()) {
                    translateX = getWidth() - displayRect.right;
                }
            }
            if (translateX != 0 || translateY != 0) {
                mOppMatrix.postTranslate(translateX, translateY);
                setDrawMatrix(countDrawMatrix());
            }

            mOppMatrix.postTranslate(translateX, translateY);
            setDrawMatrix(countDrawMatrix());
        }
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return true;
    }

    @Override
    public boolean onScaleBegin(float focusX, float focusY) {
        return true;
    }

    @Override
    public boolean onScale(float focusX, float focusY, float scale) {
        if (mTouchMode == TOUCH_SCALE_OR_MOVE) {
            if (Float.isNaN(scale) || Float.isInfinite(scale)) return false;
            Matrix drawMatrix = countDrawMatrix();
            RectF rect = getDisplayRect(drawMatrix);
            if (rect.width() * scale < getWidth() || rect.height() * scale < getHeight()) {
                drawMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
                rect = getDisplayRect(drawMatrix);
                mOppMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
                ensureRect(rect, null);
            } else {
                drawMatrix.postScale(scale, scale, focusX, focusY);
                rect = getDisplayRect(drawMatrix);
                mOppMatrix.postScale(scale, scale, focusX, focusY);
                ensureRect(rect, null);
            }
            setDrawMatrix(countDrawMatrix());
        }
        return true;
    }

    @Override
    public void onScaleEnd() {

    }

    @Override
    public boolean onRotaionBegin() {
        return false;
    }

    @Override
    public boolean onRotaion(float delta) {
        return false;
    }

    @Override
    public void onRotaionEnd() {

    }

    @Override
    public void onDown(float x, float y) {

    }

    @Override
    public void onUp(float x, float y) {
        RectF displayRect = getDisplayRect(countDrawMatrix());
        //判断需不需要复原
        float defaultWidth = mDefautDrawableRect.width();
        float defaultHeight = mDefautDrawableRect.height();
        if (displayRect.width() < defaultWidth || displayRect.height() < defaultHeight
                || displayRect.left > mDefautDrawableRect.left || displayRect.right < mDefautDrawableRect.right
                || displayRect.top > mDefautDrawableRect.top || displayRect.bottom < mDefautDrawableRect.bottom) {
            if (displayRect.width() < defaultWidth || displayRect.height() < defaultHeight) {//宽或者高比需要显示的小 需要复原
                Matrix from = new Matrix(mOppMatrix);
                mOppMatrix.reset();
                setAnimationImageMatrix(from, mOppMatrix);
            } else {//不需要复原只需要平移到合适位置
                Matrix from = new Matrix(mOppMatrix);
                if (displayRect.left > 0) {//左边
                    mOppMatrix.postTranslate(-displayRect.left, 0);
                }

                if (displayRect.top > 0) {
                    mOppMatrix.postTranslate(0, -displayRect.top);
                }

                if (displayRect.right < defaultWidth) {
                    mOppMatrix.postTranslate(defaultHeight - displayRect.right, 0);
                }

                if (displayRect.bottom < getHeight()) {
                    mOppMatrix.postTranslate(0, getHeight() - displayRect.bottom);
                }
                setAnimationImageMatrix(from, mOppMatrix);
            }
        }
    }

    @Override
    public void onLongPress(float x, float y) {

    }

    /**
     * 变形动画的持续时间（毫秒）
     */
    private static final long DURATION_MATRIX_ANIMATION = 150L;
    private boolean mIsAnimationRunning = false;
    //Matirx动画相关
    private MatrixAnimation mMatrixAnimation = null;
    private Transformation mTransformation = null;

    private CollageGestureRecognizer mGestureRecognizer;
    private int mTouchMode = TOUCH_NONE;
    private final static int TOUCH_NONE = 0;
    private final static int TOUCH_DRAW = 1;
    private final static int TOUCH_SCALE_OR_MOVE = 2;

    private boolean mIsInit = false;
    private RectF mViewRect;
    private RectF mDefautDrawableRect;

    private void initViewRect(RectF rect) {
        mViewRect.set(rect);
        mViewRect.offset(-rect.left, -rect.top);
        mIsInit = true;
        initInformation();
    }

    private Matrix countDrawMatrix() {
        mCacheMatrix.reset();
        mCacheMatrix.set(mContentSupportMatrix);
        mCacheMatrix.postConcat(mOppMatrix);
        return mCacheMatrix;
    }

    private Matrix getDrawMatrix() {
        return mDrawMatrix;
    }

    private void setDrawMatrix(Matrix matrix) {
        mDrawMatrix.set(matrix);
        invalidate();
    }

    public void reset() {
        mOppMatrix.reset();
        mIsUsingVipBrush = false;
        setDrawMatrix(countDrawMatrix());
    }

    /**
     * 获取进入状态的缩放值
     *
     * @return
     */
    private float getSupportScale() {
        RectF dst = new RectF(mDstRect);
        mContentSupportMatrix.mapRect(dst);
        float scale = dst.width() * 1.0f / mDstRect.width();
        return scale;
    }

    /**
     * 获取当前的缩放值
     *
     * @return
     */
    private float getAllScale() {
        RectF dst = new RectF(mDstRect);
        countDrawMatrix().mapRect(dst);
        float scale = dst.width() * 1.0f / mDstRect.width();
        return scale;
    }

    /**
     * 获取当前显示的Rect
     *
     * @return
     */
    private RectF getDisplayRect(Matrix matrix) {
        RectF dst = new RectF(mDstRect);
        matrix.mapRect(dst);
        return dst;
    }

    /**
     * 获取当前需要裁剪的区域
     *
     * @param matrix
     * @return
     */
    private RectF getChangedViewRect(Matrix matrix) {
        RectF dst = new RectF(mViewRect);
        matrix.mapRect(dst);
        return dst;
    }

    /**
     * 计算合适的偏移量  当前显示Rect大于View的宽高时  保证不出边界
     * 当前显示Rect小于View的宽高时  保证居中
     *
     * @param rectF
     * @param matrix 传入Matrix的话就会对Matrix执行
     */
    private void ensureRect(RectF rectF, Matrix matrix) {
        RectF mViewCacheRect = new RectF(mViewRect);
        float width = mViewRect.width();
        float height = mViewRect.height();
        float dx = 0, dy = 0;
        if (rectF.height() > height) {//对上下边的处理
            if (rectF.top > 0f) {
                dy = -rectF.top;
            } else if (rectF.bottom < height) {
                dy = height - rectF.bottom;
            }
        } else {//高度比View高度小  需要居中
            dy = (mViewCacheRect.height() - rectF.height()) / 2 + mViewCacheRect.top - rectF.top;
        }
        if (rectF.width() > width) {//对左右边的处理
            if (rectF.left > 0f) {
                dx = -rectF.left;
            } else if (rectF.right < width) {
                dx = width - rectF.right;
            }
        } else {//宽度比View高度小  需要居中
            dx = (mViewCacheRect.width() - rectF.width()) / 2 + mViewCacheRect.left - rectF.left;
        }
        if (matrix == null) {
            mOppMatrix.postTranslate(dx, dy);
        } else {
            matrix.postTranslate(dx, dy);
        }
    }

    /**
     * 使用动画模式设置矩阵对象，并实现平滑变换。设置后动画随即开始
     *
     * @param from 需要变换的目标矩阵对象
     * @param to   需要变换的目标矩阵对象
     */
    public void setAnimationImageMatrix(Matrix from, Matrix to) {
        if (!mIsAnimationRunning) {
            mIsAnimationRunning = true;

            if (mTransformation == null) {
                mTransformation = new Transformation();
            }

            if (mMatrixAnimation == null) {
                mMatrixAnimation = new MatrixAnimation(from, to);
                mMatrixAnimation.setDuration(DURATION_MATRIX_ANIMATION);
            }

            mMatrixAnimation.setFromMatrix(from);
            mMatrixAnimation.setToMatrix(to);
            mMatrixAnimation.start();
            invalidate();
        }
    }

    private void createNewDrawCanvas() {
        Bitmap newBitmap = null;
        try {
            newBitmap = Bitmap.createBitmap(
                    mExtraBitmap.getWidth(), mExtraBitmap.getHeight(), mBitmapConfig);
            this.mCanvas = new Canvas(newBitmap);
            mCanvas.drawColor(Color.TRANSPARENT);
        } catch (OutOfMemoryError er) {
            return;
        } catch (Exception e) {
            return;
        }
        // redraw the last bitmap
        if (this.mBitmap != null && !this.mBitmap.isRecycled()) {
            this.mCanvas.drawBitmap(this.mBitmap, 0, 0, this.mBitmapPaint);
            invalidate();
            this.mBitmap.recycle();
        }

        this.mBitmap = newBitmap;

        // 重置实际内容边界
        resetContentBorder((int) mViewRect.width(), (int) mViewRect.height());
    }
}